/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ucmconfchecker.conformance;

import java.util.*;
import org.jgrapht.graph.AbstractGraph;
import org.jgrapht.graph.DefaultDirectedGraph;
import org.jgrapht.graph.DefaultEdge;


/**
 *
 * @author Administrador
 */
public class ConformanceChecker<T> {
    
//    private Map<T,HashSet<T>> preconditions;

    private boolean _precedence = true;
    private boolean _missingEvent = true;
    private boolean _missingPrecondition = true;
    private boolean _unexpectedEvent = true;
    private Set<T> universeSet =null;
    
    private boolean strict= false;
    
//    private Report<T> report;
//    private Scenario<T> scenario;
    public ConformanceChecker(Collection<T> universe){       
        
        if(universe!=null){
            universeSet = new HashSet<T>(universe.size());
            universeSet.addAll(universe);
        }
//        this.scenario = scenario;
//        preconditions = new HashMap<T,HashSet<T>>();
//        for(T vertex:graph.getVertexSet()){
//            Collection<Edge> edges = graph.getInEdges(vertex);
//            HashSet<T> prec = new HashSet<T>();
//            for(Edge edge:edges){
//                if(universe==null || !universeSet.contains(graph.getSource(edge)) 
//                                  && !universeSet.contains(graph.getTarget(edge)))
//                System.out.println(edge+":: "+vertex+"<-"+graph.getSource(edge));
//                prec.add(graph.getSource(edge));
//            }
//            if(prec!=null && !prec.isEmpty())
//                preconditions.put(vertex,prec);
//        }
    }
    public static Scenario exampleGraph() {
        Scenario graph = new Scenario<String>("example");
        graph.addVertex("A");
        graph.addVertex("B");
        graph.addVertex("C");
        graph.addVertex("D");
        graph.addVertex("E");
        graph.addVertex("F");
        graph.addVertex("G");
        graph.addEdge("A", "B");
        graph.addEdge("B", "C");
        graph.addEdge("C", "D");
        graph.addEdge("D", "E");
        graph.addEdge("C", "F");
        graph.addEdge("E", "G");
        graph.addEdge("F", "G"); 
        return graph;
    }

    public static List<Event> exampleTrace() {
        List<Event> events = new ArrayList<Event>();
        Date date = new Date();
        events.add(new Event<String>(date,1L,2L,"A"));
        events.add(new Event<String>(date,2L,3L,"B"));
        events.add(new Event<String>(date,3L,5L,"C"));
        events.add(new Event<String>(date,14L,15L,"D"));
        events.add(new Event<String>(date,5L,7L,"E"));
        //events.add(new Event<String>(date,8L,10L,"F"));
        events.add(new Event<String>(date,7L,12L,"G"));
        events.add(new Event<String>(date,12L,19L,"Z1"));
        events.add(new Event<String>(date,15L,19L,"Z3"));
        events.add(new Event<String>(date,17L,19L,"Z12"));
        return events;
    }

    public Report<T> check(Scenario scenario, EventTrace<T> trace) {

//        List<Event> trace = exampleTrace();
        
        System.out.println("Events:");
        Map<T,Event<T>> events = new HashMap<T,Event<T>>();
        for(Event<T> event:trace){
//            System.out.println("+"+event);
            events.put(event.getEvent(),event);
        }
        System.out.println("Precedence checking");
        Collection<T> precSet = scenario.getVertexSet();
        Set<T> eventSet = new HashSet<T>();
        eventSet.addAll(events.keySet());
        
        Report<T> report = new Report<T>();
        
        for(Iterator<T> vertexIt=precSet.iterator();vertexIt.hasNext();){
            T vertex = vertexIt.next();
            Set<T> precs = scenario.getPreconditions(vertex);
            Event<T> currentEvent =events.get(vertex);
            System.out.println("prec: "+ vertex+"<-"+precs);
            eventSet.remove(vertex);          //marca el evento como revisado
            boolean conflict = false;
            if(currentEvent==null){
                System.out.println(vertex+"(!!!) \tmissing event");
                report.addMissingEvent(vertex);
                conflict=true;
            }else {
                for(Iterator<T> precIt=precs.iterator();precIt.hasNext();){
                    T prec = precIt.next();
                    Event precEvent = events.get(prec);
                    if(precEvent!=null){
                        if(strict && currentEvent.compareToStrict(precEvent)>0){
    //                        System.out.println(precEvent+"->"+currentEvent+" \tok");
                            precIt.remove();
                        }
                        else if(!strict && currentEvent.compareTo(precEvent)>0){
    //                        System.out.println(precEvent+"->"+currentEvent+" \tok");
                            precIt.remove();
                        }else {
                            if(isPrecedence()){
                                System.out.println(precEvent+"->"+currentEvent+" \tprecedence error");
                                report.addPrecedenceConflict(currentEvent,precEvent);
                                conflict=true;
                            }
                            precIt.remove();
                        }
                    }else if(currentEvent==null){
                        if(isMissingEvent()){
                            System.out.println(precEvent+"->["+vertex+"](!!!) \tmissing event");
                            report.addMissingEvent(vertex);
                            conflict=true;
                        }
                        precIt.remove();
                    }else if(precEvent==null){
                        if(isMissingPrecondition()){
                            System.out.println("["+prec+"](!!!)->"+currentEvent+" \tmissing precondition");
                            report.addMissingPrecondition(currentEvent,prec);
                            conflict=true;
                        }
                        precIt.remove();
                    }else{
                        if(isUnexpectedEvent()){
                            System.out.println(precEvent+"->"+currentEvent+" \tunknown");
                            if(universeSet.contains(currentEvent.getEvent())){
                                System.out.println("+"+currentEvent+" \t\tIgnored");
                                report.addUnexpectedEvent(currentEvent);
                                conflict=true;
                            }
                        }
                    }
                }if(!conflict){
                    System.out.println(""+currentEvent+" \tok");
                    report.addWidthoutConflict(vertex);
                }
            }
        }  
        return report;
//        if(_unexpectedEvent){
//            for(Iterator<T> eventIt=eventSet.iterator();eventIt.hasNext();){
//                Event<T> event =events.get(eventIt.next());
//                if(universeSet.contains(event.getEvent())){
//                    System.out.println("+"+event+" \t\tIgnored");
//                }
//            }
//        }
    }

    public boolean isPrecedence() {
        return _precedence;
    }

    public void setPrecedence(boolean precedence) {
        this._precedence = precedence;
    }

    public boolean isMissingEvent() {
        return _missingEvent;
    }

    public void setMissingEvent(boolean missinEvent) {
        this._missingEvent = missinEvent;
    }

    public boolean isMissingPrecondition() {
        return _missingPrecondition;
    }

    public void setMissingPrecondition(boolean missingPrecondition) {
        this._missingPrecondition = missingPrecondition;
    }

    public boolean isUnexpectedEvent() {
        return _unexpectedEvent;
    }

    public void setUnexpectedEvent(boolean unexpectedEvent) {
        this._unexpectedEvent = unexpectedEvent;
    }

    public void setStrictPrecedence(boolean selected) {
        this.strict = selected;
    }
    
}
